package zx.lrn.notes.basic_grammer;

import java.time.LocalDate;
import java.util.Objects;

/**
 * @ClassName: EqualsAndHashCode
 * @Description: 比较对象的方法组合：equals和hashcode的使用说明
 * @Author: zhaoxuan
 * @Date: 2020/2/25 18:54
 **/
public class EqualsAndHashCode {
    private String name;

    private int age;

    private LocalDate birthDay;

    public EqualsAndHashCode(String name, int age, int year, int month, int day) {
        this.name = name;
        this.age = age;
        LocalDate birthDay = LocalDate.of(year, month, day);
        this.birthDay = birthDay;
    }

    /**
     * JAVA中使用==比较时，对于引用类型，一定比较的是内存地址，但如果根据对象中字段值进行逻辑上的相等判定时，需要使用equals方法
     * hashcode主要用在与散列函数有关的集合中，hashcode的值决定插入元素的位置，两对象hashcode不等，则两对象一定不等，根据散列码插入到不同位置即可，
     * 但如果hashcode相等，有小概率时哈希冲突，此时再调用equals进一步判定:
     * 如果equals得true，则两对象逻辑上相等，直接覆盖原位置的元素即可，
     * 如果equals得false，说明需要解决哈希冲突（开发定址法、再哈希法、链地址法、建立一个公共溢出区）
     *
     * hashcode默认根据内存地址生成，equals默认比较内存地址，所以重写了equals就需要重写hashcode，
     * 否则逻辑相等但内存地址不同的对象所得hashcode一定不同，equals没有机会参与比较
     * 如果重写hashcode没有重写equals，在hashmap中存入逻辑相等的两对象时，会以链表形式链式存储
     *
     * @return 哈希值
     */
    @Override
    public int hashCode() {
        return Objects.hash(this.name, this.age, this.birthDay);
    }

    @Override
    public boolean equals(Object otherObject) {
        // 1、用==比较，该机制消耗很小
        if (this == otherObject) {
            return true;
        }
        // 2、校验入参是否为null
        if (otherObject == null) {
            return false;
        }
        // 3、检验入参类型，如果相等性由父类的成员变量决定，那应该instanceOf 父Class，如果相等性由子类决定，那应该使用getClass()==getClass()
        if (getClass() != otherObject.getClass()) {
            return false;
        }
        // 4、强转入参的类型
        EqualsAndHashCode other = (EqualsAndHashCode)otherObject;
        // 5、进行两个对象的字段值
        return Objects.equals(this.name, other.name) && Objects.equals(this.age, other.age)
            && Objects.equals(this.birthDay, other.birthDay);
    }

    public static void main(String[] args) {
        EqualsAndHashCode a = new EqualsAndHashCode("a", 12, 2000, 2, 20);
        EqualsAndHashCode b = new EqualsAndHashCode("b", 12, 2000, 2, 20);
        EqualsAndHashCode c = new EqualsAndHashCode("a", 12, 2000, 2, 20);

        System.out.println(a.equals(b));
        System.out.println(a.equals(c));
        System.out.println(a.hashCode());
        System.out.println(b.hashCode());
        System.out.println(c.hashCode());
    }
}
